package com.sixnimmt.app.shared.game.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;

public class Board implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public static final int STACK_NUMBER = 4;
	public static final int STACK_MAX_SIZE = 5;
	private final Stack[] stacks;

	public Board() {
		this.stacks = new Stack[STACK_NUMBER];
		for (int i = 0; i < STACK_NUMBER; i++) {
			this.stacks[i] = new Stack();
		}
	}

	public void init(Card[] initialCards) {
		for (int i = 0; i < initialCards.length; i++) {
			stacks[i].clearStack();
			stacks[i].addCard(initialCards[i]);
		}
	}

	public PlayCardResult playCard(Card card) {
		return playCard(card, -1);
	}

	public PlayCardResult playCard(Card card, int stack) {
		if (card.getValue() < getMinValueCardForAllStack().getValue()) {
			return takeStackAndAddCard(card, stack);
		} else {
			stack = getStackIndexToPlay(card);
			if (stacks[stack].getSize() == STACK_MAX_SIZE) {
				return takeStackAndAddCard(card, stack);
			} else {
				stacks[stack].addCard(card);
				return new PlayCardResult(new LinkedHashSet<Card>(), stack, stacks[stack].getCards().size() - 1);
			}
		}

	}

	private PlayCardResult takeStackAndAddCard(Card card, int stack) {
		LinkedHashSet<Card> takenCards = new LinkedHashSet<Card>();
		takenCards.addAll(stacks[stack].getCards());
		stacks[stack].clearStack();
		stacks[stack].addCard(card);
		return new PlayCardResult(takenCards, stack, 0);
	}

	public Card getMinValueCardForAllStack() {
		Card minCard = stacks[0].getLastCard();
		for (int i = 1; i < STACK_NUMBER; i++) {
			Card current = stacks[i].getLastCard();
			if (current.getValue() < minCard.getValue()) {
				minCard = current;
			}
		}
		return minCard;
	}

	protected int getMinPointsStackIndex() {
		int result = 0;
		int points = stacks[0].getPointsInStack();
		for (int i = 1; i < STACK_NUMBER; i++) {
			int current = stacks[i].getPointsInStack();
			if (current < points) {
				points = current;
				result = i;
			}
		}
		return result;
	}

	private int getStackIndexToPlay(Card card) {
		List<Integer> values = new ArrayList<Integer>();
		for (int i = 0; i < STACK_NUMBER; i++) {
			values.add(stacks[i].getLastCard().getValue());
		}
		Collections.sort(values, Collections.reverseOrder());
		int topCardValue = 0;
		for (Integer value : values) {
			if (value < card.getValue()) {
				topCardValue = value;
				break;
			}
		}
		for (int i = 0; i < STACK_NUMBER; i++) {
			if (topCardValue == stacks[i].getLastCard().getValue()) {
				return i;
			}
		}
		return -1;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < STACK_NUMBER; i++) {
			sb.append(this.stacks[i].toString() + "\r\n");
		}
		return sb.toString();
	}

	public Stack[] getStacks() {
		return stacks;
	}

}
